package com.ops.chirpit;

import java.util.Arrays;
import java.util.Iterator;
import java.util.Map;

import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;

import twitter4j.GeoLocation;
import twitter4j.GeoQuery;
import twitter4j.IDs;
import twitter4j.Place;
import twitter4j.ResponseList;
import twitter4j.Twitter;
import twitter4j.User;
import twitter4j.auth.AccessToken;
import android.location.Location;
import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
import android.util.Log;

import com.facebook.android.Facebook;
import com.facebook.android.Util;

import fi.foyt.foursquare.api.FoursquareApi;
import fi.foyt.foursquare.api.FoursquareApiException;
import fi.foyt.foursquare.api.Result;
import fi.foyt.foursquare.api.entities.CompactVenue;
import fi.foyt.foursquare.api.entities.VenuesSearchResult;

public class ProgressThread extends Thread{
    Handler mHandler;
    public final static int STATE_DONE = -1;
	static final int STATE_RUNNING = 1;
    int mState, total = 0, mId;
   
    public ProgressThread(Handler h, int id) {
        mHandler = h;
        mId = id;
    }

	public void run() {
        Message msg = mHandler.obtainMessage();
        mState = STATE_RUNNING;
        int a = 0, p = 0;
        switch(mId){
        case ChirpItActivity.LOAD_ACCOUNTS:
        	ChirpItActivity.accounts = new JSONArray();
        	Map<String, ?> mPrefMap = ChirpItActivity.prefMap;
        	int numOfPrefs = mPrefMap.size();
            for(String pref : mPrefMap.keySet()){
            	JSONObject account = new JSONObject();
            	if (pref != null && pref.contains("_token_")){
    	        	try {
    	        		String id = pref.substring(9).toString();
    	        		String token = mPrefMap.get(pref).toString();
    	        		int prefixIndex = AccountType.getPrefixIndex(pref);
    	        		String secret = (String) mPrefMap.get(ChirpItActivity.accountTypes[prefixIndex].prefix + "_secret_" + id);
    	        		String name = (String) mPrefMap.get(ChirpItActivity.accountTypes[prefixIndex].prefix + "_name_" + id);
		        		account.put("id", id);
		        		account.put("token", token);
		        		account.put("secret", secret);
		        		account.put("name", name);
		        		account.put("network", prefixIndex);
		        		ChirpItActivity.accounts.put(account); a++;
		        		switch(prefixIndex){
			        		case ChirpItActivity.TWITTER:
	    		        		AccessToken at = new AccessToken(token, secret);
		        				ChirpItActivity.twitter.setOAuthConsumer(AuthActivity.twConsumerKey, AuthActivity.twConsumerSecret);
	    		        		ChirpItActivity.twitter.setOAuthAccessToken(at);
	    		        		break;
			        		case ChirpItActivity.FACEBOOK:
	    		        		ChirpItActivity.authenticatedFacebook.setAccessToken(token);
	    		        		ChirpItActivity.authenticatedFacebook.setAccessExpiresIn("0");
	    		        		JSONArray fbPages = AuthActivity.getFBPages().getJSONArray("data");
	    		        		for(int i = 0; i < fbPages.length(); i++){
	    		        			account = new JSONObject();
	    		        			account.put("id", ((JSONObject) fbPages.get(i)).getString("id"));
	    			        		account.put("token", ((JSONObject) fbPages.get(i)).getString("access_token"));
	    			        		account.put("secret", secret);
	    			        		account.put("name", ((JSONObject) fbPages.get(i)).getString("name"));
	    			        		account.put("network", prefixIndex);
	    			        		ChirpItActivity.accounts.put(account); a++;
	    		        		}
	    		        		break;
			        		case ChirpItActivity.FOURSQUARE:
	    		        		ChirpItActivity.foursquareApi.setoAuthToken(token);
	    		        		break;
		        		}
    		        	Thread.sleep(300);
    	        	} catch (Exception e) {
    	        		// TODO Auto-generated catch block
    	        		e.printStackTrace();
    	        	}
            	}
            	p++;
                Message msg1 = mHandler.obtainMessage();
		        msg1.arg1 = p;
		        msg1.arg2 = numOfPrefs;
		        mHandler.sendMessage(msg1);
            }
            break;
        case ChirpItActivity.PLACES:
        	JSONArray placeList = new JSONArray();
      	  	Result<VenuesSearchResult> fosqVenues = null;
      	  	ChirpItActivity.location = LocationActivity.updateLocation();
      	  	Location searchLocation = ChirpItActivity.location;

	      	  //JSONObject fosqPlaces = new JSONObject();
	      	  ResponseList<Place> twPlaces = twitterGeoSearch(searchLocation, LocationActivity.query);
	      	  JSONObject fbPlaces = searchPlaces(searchLocation, LocationActivity.query);
	      	  JSONObject place = new JSONObject();
	      	  JSONArray fbPlacesArray;
	      	  Location placeLocation = new Location("0,0");
	      	  try {
	      		  if(!twPlaces.isEmpty()){
		  			  for (Iterator<Place> iterator = twPlaces.iterator(); iterator.hasNext();){
		  				  Place twP = iterator.next();
		  				  GeoLocation[][] gLC = twP.getGeometryCoordinates();
		  				  if(gLC != null){
			  				  placeLocation.setLatitude(gLC[0][0].getLatitude());
			  				  placeLocation.setLongitude(gLC[0][0].getLongitude());
			  				  place.put("distance", Math.round(LocationActivity.getDistance(searchLocation, placeLocation)));
		  				  }
		  				  place.put("id", twP.getId());
		  				  place.put("name", twP.getName());	  				  
		  				  place.put("provider", ChirpItActivity.TWITTER);
		  				  placeList.put(place);
		  				  place = new JSONObject();
		  			  }
	      		  }
	      		  fosqVenues = searchVenues(searchLocation, LocationActivity.query);
	      		  if(fosqVenues != null){
		      		  for (CompactVenue venue : fosqVenues.getResult().getVenues()) {
		      			  // TODO: Do something we the data
		      			  place.put("id", venue.getId());
		      			  place.put("name", venue.getName());
		      			  place.put("distance", venue.getLocation().getDistance());
		      			  place.put("provider", ChirpItActivity.FOURSQUARE);
		      			  placeList.put(place);
		      			  place = new JSONObject();
		      	      }
	      		  }
	      		  if(!fbPlaces.isNull("data")){
	      			  fbPlacesArray = fbPlaces.getJSONArray("data");
		      		  for (p = 0;p < fbPlacesArray.length(); p++){
		      	    	  place = (JSONObject) fbPlacesArray.get(p);
		      	    	  placeLocation.setLatitude(place.getJSONObject("location").getDouble("latitude"));
		      	    	  placeLocation.setLongitude(place.getJSONObject("location").getDouble("longitude"));
		      	    	  place.put("distance", Math.round(LocationActivity.getDistance(searchLocation, placeLocation)));
		      			  place.put("provider", ChirpItActivity.FACEBOOK);
		      	    	  placeList.put(place);
		      	    	  place = new JSONObject();
		      		  }	      
	      		  }
	      		 
	      	} catch (JSONException e) {
	      		// TODO Auto-generated catch block
	      		e.printStackTrace();
	      	}	  
	      	  msg.obj = placeList;
        	break;
        case ChirpItActivity.FRIENDS:
        	JSONArray friendList = null;
	        try {       		
	        	JSONArray fbFriends = getFriends("");
	        	JSONArray twFriends = getTWFriends("");  
	        	int friendCount = fbFriends.length() + twFriends.length();
	        	JSorter[] friends = new JSorter[friendCount];
				for (int i = 0; i < fbFriends.length(); i++){
					JSONObject friend = fbFriends.getJSONObject(i);
					friends[i] = new JSorter(friend, 
							ChirpItActivity.FACEBOOK, "name");
				}
				int f = fbFriends.length();
				for (int i = 0; i < twFriends.length(); i++){
					JSONObject friend = twFriends.getJSONObject(i);
					friends[f+i] = new JSorter(friend, 
							ChirpItActivity.TWITTER, "name");
				}
				Arrays.sort(friends);
				friendList = new JSONArray();
				for (int i = 0; i < friends.length; i++){
					friends[i].mJObject.put("provider", friends[i].network);
					friendList.put(friends[i].mJObject);
				}  	
			} catch (JSONException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
			msg.obj = friendList;
        	break;
        }
        msg.arg1 = 100;
        msg.arg2 = 100;
        if (mState != STATE_DONE)
        	mHandler.sendMessage(msg);
    }
    
    /* sets the current state for the thread, used to stop the thread */
	public void setState(int state) {
		// TODO Auto-generated method stub
        mState = state;
	}
	
	public static ResponseList<Place> twitterGeoSearch(Location location, String query){
		Twitter tw = ChirpItActivity.twitter;
		GeoLocation gL = new GeoLocation(location.getLatitude(), location.getLongitude());
		GeoQuery gQ = new GeoQuery(gL);
		int limit = Integer.parseInt(ChirpItActivity.locationListLength);
		if(query == ""){
			gQ.setMaxResults(limit);
			gQ.setGranularity("poi");
		}else {
			gQ.setMaxResults(3);
			gQ.setGranularity("neighborhood");
		}
		try {
			ResponseList<Place> rLP = tw.searchPlaces(gQ);
			return rLP;
		} catch (Exception e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		return null;
	}
	
	public static Result<VenuesSearchResult> searchVenues(Location location, String query){
	    // First we need a initialize FoursquareApi. 
	    FoursquareApi fsApi = ChirpItActivity.foursquareApi;

  	  	String ll = location.getLatitude() + "," + location.getLongitude();
  	  	double llAcc = location.getAccuracy();
  	  	double alt = location.getAltitude();
	    // After client has been initialized we can make queries.
	    Result<VenuesSearchResult> result;
		try {
			result = fsApi.venuesSearch(ll, llAcc, alt, null, query, Integer.parseInt(ChirpItActivity.locationListLength), null, null, null, null, null);
		    int resultCode = (int)result.getMeta().getCode();
		    if (resultCode == 200) {
		      return result;
		    } else {
		      // TODO: Proper error handling
		      System.out.println("Error occured: ");
		      System.out.println("  code: " + result.getMeta().getCode());
		      System.out.println("  type: " + result.getMeta().getErrorType());
		      System.out.println("  detail: " + result.getMeta().getErrorDetail()); 
		      return null;
		    }
		} catch (FoursquareApiException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
			return null;
		}
	  }
	
	public static JSONObject searchPlaces(Location location, String query){
		Facebook authdFacebook = ChirpItActivity.authenticatedFacebook;
		if (!authdFacebook.isSessionValid()) return null;
        try {
            Log.d("Tests", "Testing request for 'me'");
            String response = authdFacebook.request("me");
            JSONObject obj = Util.parseJson(response);
            if (obj.getString("name") == null || 
                    obj.getString("name").equals("")) {
                return null;
            }response = "";
            
            Log.d("Tests", "Testing graph API place search");
            Bundle parameters = new Bundle();
            parameters.putString("type", "place");
            parameters.putString("center", String.format("%f,%f", location.getLatitude(), location.getLongitude()));
            parameters.putString("distance", "2000");
            if (query != ""){
            	parameters.putString("q", query);
            	parameters.putString("distance", "5000");
            }
            parameters.putString("limit", ChirpItActivity.locationListLength);

            response = authdFacebook.request("search", parameters, 
                    "GET");
            //Log.d("Tests", "got response: " + response);
            if (response == null || response.equals("") || 
                    response.equals("false")) {
                return null;
            }
            
            Log.d("Tests", "All Authenticated Tests Passed");
            return Util.parseJson(response);
        } catch (Throwable e) {
            e.printStackTrace();
            return null;
        }
	}
	
	public static JSONArray getFriends(String query){
		Facebook authdFacebook = ChirpItActivity.authenticatedFacebook;
		if (!authdFacebook.isSessionValid()) return null;
        try {
            String response = "";
            Bundle parameters = new Bundle();
            if (query != ""){
            	parameters.putString("q", query);
            }

            response = authdFacebook.request("me/friends", parameters, 
                    "GET");
            Log.d("Tests", "got response: " + response);
            if (response == null || response.equals("") || 
                    response.equals("false")) {
                return null;
            }
            
            Log.d("Tests", "All Authenticated Tests Passed");
            return Util.parseJson(response).getJSONArray("data");
        } catch (Throwable e) {
            e.printStackTrace();
            return null;
        }
	}
	
	public static JSONArray getTWFriends(String query){
			Twitter tw = ChirpItActivity.twitter;
			JSONObject friend = new JSONObject();
			JSONArray friends = new JSONArray();
		try {
			IDs friendIDs = tw.getFriendsIDs(-1L);
			ResponseList<User> users = tw.lookupUsers(friendIDs.getIDs());
			for (Iterator<User> iterator = users.iterator(); iterator.hasNext();){
				User user = iterator.next();
				friend.put("id", user.getId());
				friend.put("name", user.getName());
				friend.put("screenName", user.getScreenName());
				friends.put(friend);
				friend = new JSONObject();
			}
		} catch (Exception e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} 
		return friends;		
	}
}